#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <unistd.h>
#include <cstdio>
#include <vector>
#include <functional>
#include <sys/wait.h>
#include "Task.hpp"
#include "Channel.hpp"
using work_t = function<void()>;
using namespace std;

enum
{
    OK = 0,
    UsageError,
    PipeError,
    ForkError,
};

class ProcessPool
{
public:
    ProcessPool(int n, work_t w)
        : num(n), work(w)
    {
    }

    // channels: 输出型参数
    // work_t work：回调
    int InitProcessPool()
    {
        // 2. 创建
        for (int i = 0; i < num; i++)
        {
            // 1. 先有管道
            int pipefd[2] = {0};
            int n = pipe(pipefd);
            if (n < 0)
                return PipeError;
            pid_t id = fork();
            if (id < 0)
                return ForkError;

            // 建立通讯管道
            // child
            if (id == 0)
            {
                // read
                ::close(pipefd[1]);

                dup2(pipefd[0], 0);
                work();
                cout << "child->" <<getpid() <<"done ........Task" << endl;
                ::exit(0); // 执行完就say bye
            }

            // parent
            // write
            ::close(pipefd[0]);
            channels.emplace_back(pipefd[1], id);
            // Channel ch(pipefd[1],id);
            // channels.push_back(ch);
        }
        return OK;
    }

    void DispatchTask()
    {
        int who = 0;
        // 2. 派发任务
        int num = 10;

        while (num--)
        {
            // a.选择一个任务
            int task = tm.SelectTask();
            // b.选择一个子进程channel
            Channel &curr = channels[who++];
            who %= channels.size();

            cout << "-------------------------------------" << endl;
            cout << "send this " << task << " to " <<curr.Name() << ",  任务还剩: " << num << endl;
            cout << "-------------------------------------" << endl;
            cout << "                                     " << endl;
            cout << "                                     " << endl;
            cout << "                                     " << endl;
            cout << "                                     " << endl;
            // c.派发任务
            curr.Send(task);

            sleep(1);
        }
    }

    void CleanProcessPool()
    {
        // 为什么不能关掉一个读端，关一个进程
        // version 2 ---
        // 管道写端正常&&读端关闭，OS会直接杀掉写入的进程！
        for (int i = channels.size() - 1; i >= 0; i--)
        {
            channels[i].Close();
            pid_t rid = ::waitpid(channels[i].who(), nullptr, 0);
            if (rid > 0)
            {
                cout << "child " << rid << "wait...success " << "quit..." << endl;
            }
        }
        // for (auto &c : channels)
        // {
        //     c.Close();
        //     pid_t rid = ::waitpid(c.who(), nullptr, 0);
        //     if (rid > 0)
        //     {
        //         cout << "child " << rid << "wait...success " << "quit..." << endl;
        //     }
        // }

        // version 1 ---
        // for (auto &c : channels)
        // {
        //     c.Close();
        // }

        // for (auto &e : channels)
        // {
        //     pid_t rid = ::waitpid(e.who(), nullptr, 0);
        //     if (rid > 0)
        //     {
        //         cout << "child " << rid << "wait...success " << "quit..." << endl;
        //     }
        // }
    }

private:
    vector<Channel> channels;
    int num;
    work_t work;
};
